package com.bensonbasement.snorflux.client;

import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.net.InetSocketAddress;

import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;

import com.bensonbasement.snorflux.server.SnorfluxServerHandler;

public class SnorfluxGUI extends JFrame implements SnorfluxClient.ClientStatusListener {
	
	public static void main(String[] args) {
		SnorfluxGUI gui = new SnorfluxGUI();
		gui.setMinimumSize(new Dimension(512,600));
		gui.setVisible(true);
	}
	
	private JMenuItem connectMenuItem;
	private JMenuItem disconnectMenuItem;
	
	private JMenuItem startServerMenuItem;
	private JMenuItem startGameMenuItem;
	private JMenuItem stopServerMenuItem;
	private JMenuItem saveGameMenuItem;
	
	private SnorfluxClient client = null;
	private SnorfluxServerHandler server = null;
	
	public SnorfluxGUI() {
		super("Snorflux Swing Client");
		
		this.setDefaultCloseOperation(EXIT_ON_CLOSE);
		
		this.connectMenuItem = new JMenuItem("Connect to remote server...");
		this.connectMenuItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				showConnectDialog();
			}
		});
		
		this.disconnectMenuItem = new JMenuItem("Disconnect");
		disconnectMenuItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				disconnect();
			}
			
		});
		
		JMenu clientMenu = new JMenu("Client");
		clientMenu.add(connectMenuItem);
		clientMenu.add(disconnectMenuItem);
		
		
		this.startServerMenuItem = new JMenuItem("Start server...");
		this.startServerMenuItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				SnorfluxGUI.this.startServer();
			}
		});
		this.stopServerMenuItem = new JMenuItem("Stop server");
		this.stopServerMenuItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				SnorfluxGUI.this.stopServer();
			}
		});
		
		this.startGameMenuItem = new JMenuItem("Start game");
		this.startGameMenuItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				SnorfluxGUI.this.server.startGame();
			}
		});
		
		this.saveGameMenuItem = new JMenuItem("Save game");
		this.saveGameMenuItem.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				JFileChooser fileChooser = new JFileChooser();
				int result = fileChooser.showSaveDialog(SnorfluxGUI.this);
				if (result == JFileChooser.APPROVE_OPTION) {
					File file = fileChooser.getSelectedFile();
					SnorfluxGUI.this.server.saveGame(file);
				}
			}
		});
		
		JMenu serverMenu = new JMenu("Server");
		serverMenu.add(startServerMenuItem);
		serverMenu.add(stopServerMenuItem);
		serverMenu.add(startGameMenuItem);
		serverMenu.add(saveGameMenuItem);
		
		JMenuBar menuBar = new JMenuBar();
		menuBar.add(clientMenu);
		menuBar.add(serverMenu);
		this.setJMenuBar(menuBar);
		
		this.addWindowListener(new WindowListener() {
			@Override
			public void windowActivated(WindowEvent arg0) {}
			@Override
			public void windowClosed(WindowEvent arg0) {}
			@Override
			public synchronized void windowClosing(WindowEvent arg0) {
				disconnect();
				stopServer();
			}
			@Override
			public void windowDeactivated(WindowEvent arg0) {}
			@Override
			public void windowDeiconified(WindowEvent arg0) {}
			@Override
			public void windowIconified(WindowEvent arg0) {}
			@Override
			public void windowOpened(WindowEvent arg0) {}
		});
		
		this.updateEnabledStatus();
		this.pack();
		
	}
	
	private void showConnectDialog() {
		final ConnectDialog connectDialog = new ConnectDialog(this);
		connectDialog.setVisible(true);
		if (connectDialog.connectRequested()) {
			InetSocketAddress address = new InetSocketAddress(connectDialog.getHostname(),connectDialog.getPort());
			connectToRemoteServer(address, connectDialog.getPlayerName());
		}
	}
	
	public void connectToRemoteServer(InetSocketAddress address, String playerName) {
		if (client != null) {
			assert client.isFinished();
			remove(client.getGamePanel());
		}
		client = new SnorfluxClient(this,address,playerName);
		add(client.getGamePanel());
		this.updateEnabledStatus();
	}
	
	public void disconnect() {
		if (client != null) {
			client.disconnect();
			updateEnabledStatus();
		}
	}
	
	private void startServer() {
		final StartServerDialog startServerDialog = new StartServerDialog(SnorfluxGUI.this);
		startServerDialog.setVisible(true);
		if (startServerDialog.startServerRequested()) {
			// Start the server
			server = new SnorfluxServerHandler(startServerDialog.getPort(),startServerDialog.getSaveFile());
			server.startServer();
			
			if (startServerDialog.connectRequested()) {
				// Connect to the server
				InetSocketAddress address = new InetSocketAddress("localhost",startServerDialog.getPort());
				connectToRemoteServer(address,startServerDialog.getPlayerName());
			}
			this.updateEnabledStatus();
		}
	}
	
	private void stopServer() {
		if (server != null) {
			server.stopServer();
			server = null;
			updateEnabledStatus();
		}
	}
	
	private void updateEnabledStatus() {
		boolean connectedToGame = client != null && !client.isFinished();
		connectMenuItem.setEnabled(server == null && !connectedToGame);
		disconnectMenuItem.setEnabled(server == null && connectedToGame);
		startServerMenuItem.setEnabled(server == null && !connectedToGame);
		stopServerMenuItem.setEnabled(server != null);
		startGameMenuItem.setEnabled(server != null && !server.isGameRunning());
		saveGameMenuItem.setEnabled(server != null && server.isGameRunning());
	}
	
	@Override
	public void clientStatusChanged() {
		updateEnabledStatus();
	}
}
